package de.hs.rm.UJAdapter.factory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;

import javax.management.MBeanAttributeInfo;
import javax.management.openmbean.ArrayType;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import javax.management.openmbean.TabularType;

import org.osgi.service.upnp.UPnPStateVariable;

import de.hs.rm.UJAdapter.impl.UJStateVariable;
import de.hs.rm.UJAdapter.impl.UJStateVariableOpenType;
import de.hs.rm.UJAdapter.util.ClassTypeUtil;

public class UJStateVariableFactory {
	public static UJStateVariable createStateVariable(MBeanAttributeInfo mbeanAttribute)
	{
		UJStateVariable stateVariable = new UJStateVariable();
    	stateVariable.setName(mbeanAttribute.getName());
    	stateVariable.setJavaDataType(
    			ClassTypeUtil.getJavaDataTypeFromString(mbeanAttribute.getType()));
       	stateVariable.setUPnPDataType(
       			ClassTypeUtil.getUPNPDataTypeFromString(mbeanAttribute.getType()));
    	stateVariable.setIs(mbeanAttribute.isIs());
    	stateVariable.setReadable(mbeanAttribute.isReadable());
    	stateVariable.setWritable(mbeanAttribute.isWritable());
    	return stateVariable;
	}
	
	public static UJStateVariable createActionStateVariable(String UPnPType, String JavaType)
	{
		UJStateVariable stateVariable = new UJStateVariable();
    	stateVariable.setName("A_ARG_TYPE_" + UPnPType);
    	stateVariable.setJavaDataType(
    			ClassTypeUtil.getJavaDataTypeFromString(JavaType));
       	stateVariable.setUPnPDataType(UPnPType);
       	return stateVariable;	
	}
	
	public static UJStateVariable createNotificationStateVariable(String notificationName)
	{
		UJStateVariable stateVariable = new UJStateVariable();
    	stateVariable.setName(notificationName);
    	stateVariable.setJavaDataType(String.class);
       	stateVariable.setUPnPDataType(UPnPStateVariable.TYPE_STRING);
       	return stateVariable;	
	}
	
	public static UJStateVariable createSimpleTypeStateVariable(SimpleType simpleType, String UPnPTypeName)
	{
		UJStateVariable stateVariable = new UJStateVariable();
		stateVariable.setName("A_ARG_TYPE_" + UPnPTypeName);
    	stateVariable.setJavaDataType(
    			ClassTypeUtil.getJavaDataTypefromSimpleType(simpleType.getTypeName()));
       	stateVariable.setUPnPDataType(UPnPTypeName);
       	return stateVariable;
	}
	public static UJStateVariable createOpenTypeStateVariable(OpenMBeanAttributeInfoSupport openMBeanAttr)//, String name, Class javaClass)
	{
		UJStateVariableOpenType stateVariable = new UJStateVariableOpenType();
		stateVariable.setName("COMPLEX_TYPE_" + openMBeanAttr.getName());
		
		OpenType openType = openMBeanAttr.getOpenType(); 
		
		stateVariable.setAttributeName(openMBeanAttr.getName());
		stateVariable.setOpenType(openType);
		
		//String description = openType.toString();//createOpenTypeDescription(openMBeanAttr.getOpenType());
		
		stateVariable.setDescription(openType.toString());
    	stateVariable.setJavaDataType(openType.getClass());
       	stateVariable.setReadable(openMBeanAttr.isReadable());
    	stateVariable.setWritable(openMBeanAttr.isWritable());
       	return stateVariable;
	}
	
	private static String createOpenTypeDescription(OpenType openType) {
		String desc = "";		
		String openTypeClassString = openType.toString();
		
		//recursively add simple type state variables from complex types
		switch(ClassTypeUtil.getOpenType(openTypeClassString))
		{
			case ClassTypeUtil.OPENTYPE_COMPOSITE:
				//System.out.println(openMBeanAttr.getName() +": " + ClassTypeUtil.OPENTYPE_COMPOSITE);
				CompositeType compType= (CompositeType) openType;
				Set<String> keys = compType.keySet();
    			Iterator<String> it = keys.iterator();
    			desc = "CompositeType[Desc:" + compType.getDescription() + ";Attributes:";
    			while(it.hasNext())
    			{
    				String key = it.next();
    				desc = desc + key + "[Type:" + createOpenTypeDescription(compType.getType(key)) +"],"; 
    			}
    			desc =  desc + "]";
			break;
			
			case ClassTypeUtil.OPENTYPE_ARRAY:
				ArrayType arrayType = (ArrayType) openType;
				desc = "ArrayType[Type:" + createOpenTypeDescription(arrayType.getElementOpenType()) + "]";
				//createOpenTypeDescription(arrayType.getElementOpenType(), description);
			break;
				
			case ClassTypeUtil.OPENTYPE_TABULAR:
				TabularType tabType = (TabularType) openType;
				desc = "TabularType[Type:" + createOpenTypeDescription(tabType.getRowType()) + "]";
				
				//createOpenTypeDescription(tabType.getRowType(), description);
			break;
			
			case ClassTypeUtil.OPENTYPE_SIMPLE:
				SimpleType simpleType = (SimpleType) openType;
				String UPnPTypeName = ClassTypeUtil.getUPnPDataTypefromSimpleType(simpleType.getTypeName());
				desc = UPnPTypeName;
				
				//				System.out.println("sT: " +simpleType.getTypeName());
				//only add state variable if it doesn't exist
				//return description;
			break;
		}
		return desc;
	}

	public static void createOpenTypeStateVariableList(OpenType openType, ArrayList<UJStateVariable> openStateVariablesList)
	{
		String openTypeClassString = openType.toString();
//		System.out.println("========================");
//		System.out.println(openTypeClassString);
//		System.out.println(openType.getClassName());
//		System.out.println(openType.getDescription());
//		System.out.println(openType.getClass().toString());
//		System.out.println(openType.getTypeName());

		
		//recursively add simple type state variables from complex types
		switch(ClassTypeUtil.getOpenType(openTypeClassString))
		{
			case ClassTypeUtil.OPENTYPE_COMPOSITE:
				//System.out.println(openMBeanAttr.getName() +": " + ClassTypeUtil.OPENTYPE_COMPOSITE);
				CompositeType compType= (CompositeType) openType;
				Set<String> keys = compType.keySet();
    			Iterator<String> it = keys.iterator();    			
    			while(it.hasNext())
    			{
    				String key = it.next();
    				createOpenTypeStateVariableList(compType.getType(key), openStateVariablesList);
//    				System.out.println("\t" + key + ": "
//    						+ ClassTypeUtil.getOpenType(compType.getType(key).toString()));
    			}	
			break;
			
			case ClassTypeUtil.OPENTYPE_ARRAY:
				ArrayType arrayType = (ArrayType) openType;
				createOpenTypeStateVariableList(arrayType.getElementOpenType(), openStateVariablesList);
			break;
				
			case ClassTypeUtil.OPENTYPE_TABULAR:
				TabularType tabType = (TabularType) openType;				
				createOpenTypeStateVariableList(tabType.getRowType(), openStateVariablesList);
			break;
			
			case ClassTypeUtil.OPENTYPE_SIMPLE:
				SimpleType simpleType = (SimpleType) openType;
				String UPnPTypeName = ClassTypeUtil.getUPnPDataTypefromSimpleType(simpleType.getTypeName());
//				System.out.println("sT: " +simpleType.getTypeName());
				//only add state variable if it doesn't exist
				boolean osvExists = false;
				for (UJStateVariable osv : openStateVariablesList)
					if (osv.getUPnPDataType().equals(UPnPTypeName))
						osvExists = true;
				if(!osvExists)
					openStateVariablesList.add(createSimpleTypeStateVariable(simpleType, UPnPTypeName));
			break;
		}
	}
}
